import atlas
from atlas import web, hdf, sql
from atlas.plotting import chart
from atlas.plotting.const import *
from mod454 import schema
from itertools import cycle
from atlas.plotting import tracks

SHOW_LABEL_LIMIT = 10000

def open_databases( conf ):
    """
    A helper function that returns handles to the hdf and sql databases
    """
    db = hdf.hdf_open( conf.HDF_DATABASE, mode='r' )
    session = sql.get_session( conf.SQL_URI )
    return db, session

def build_tracks( param, conf, data_label, fit_label, pred_label, strand, show=False ):
    """
    Builds tracks
    """
    
    # gets all the labels for a fast lookup
    label_cache = web.label_cache( conf )       

    # get database handles for hdf and sql
    db, session = open_databases( conf )

    # fetching x and y coordinates for bar and fit (line) for 
    # each strand plus (p), minus (m), all (a) 
    bix, bpy, bmy, bay = schema.hdf_query( db=db, name=data_label, param=param, autosize=True )
    fix, fpy, fmy, fay = schema.hdf_query( db=db, name=fit_label, param=param, autosize=True )

    # close the hdf database
    db.close()

    # get all features within the range
    sql_feat = web.feature_query( session=session,  param=param )

    # set the scale of the plot        
    xscale =[ param.start, param.end ]

    # when visualizing on wide scales labels are not useful
    xspan  = ( param.end - param.start )
    show_labels = False

    # collect charts here        
    charts = []

    # this will cycle the background color for the tracks
    bgColors = cycle( [LIGHT, WHITE] )

    #
    # draw the data chart on top
    #
    if strand == 'composite':
        
        # composite plot
        baropts = chart_options( 
            xscale=xscale, fgColor=PURPLE, 
            XAxisOnTop=1, bpad=0, edgeColor=GREY, ylabel='Reads', 
            ylabel2='Fit', w=param.width, lw=2 
        )
        
        bar = tracks.fitted_data( 
            line_x=fix, line_y=fay, 
            bars_x=bix, bars_y=bay, 
            options=baropts 
        )
    else:
        
        # mirrored two strand plot
        baropts = chart_options( 
            xscale=xscale,
            XAxisOnTop=1, bpad=0, edgeColor=GREY, ylabel='Reads', 
            ylabel2='Fit', w=param.width, lw=2 
        )
        
        # not so pretty
        bar = tracks.mirrored_fitted_data( 
            line_upx=fix, line_upy=fpy,
            bars_upx=bix, bars_upy=bpy,
            line_dwx=fix, line_dwy=fmy,
            bars_dwx=bix, bars_dwy=bmy,
            options=baropts 
        )
    
    charts.append( bar )            

    #
    # generate a nucleosome track
    #
    if True:
        value = float( param.min_fit ) or 2
     
        if strand == 'composite':
            
            nfeats = web.feature_filter(data=sql_feat, name=pred_label, strand='A', value=value, kdict=label_cache)
            ndata  = web.feature2data( nfeats )
            
            nucopts = track_options( 
                xscale=xscale, w=param.width, fgColor=PURPLE,
                show_labels=show_labels, ylabel='Nucl',
                bgColor=WHITE
            )
            nuc_track = tracks.simple_track( data=ndata, options=nucopts ) 
        
        else:
        
            nucopts = track_options( 
                xscale=xscale, w=param.width, fgColor=PURPLE,
                show_labels=False, ylabel='Nucl',
                bgColor=WHITE 
            )
            nfeatures = web.feature_filter(data=sql_feat, name=pred_label, value=value, kdict=label_cache)
            nuc_track = tracks.split_tracks( features=nfeatures, options=nucopts, split=True ) 

        charts.append( nuc_track )
    
    if pred_label in ( 'PRED-gerald-yeast-73-SIGMA-20', 'PRED-gerald-yeast-73-SIGMA-5'):
        if pred_label == 'PRED-gerald-yeast-73-SIGMA-20':
            nim_label = 'PRED-nimble-oid-9390-SIGMA-20'
        else:
            nim_label = 'PRED-nimble-oid-9390-SIGMA-15'
        # show nimblegen as well data
        nimfeats = web.feature_filter(data=sql_feat, name=nim_label, strand='A', kdict=label_cache)
        nimdata  = web.feature2data( nimfeats )
                
        nimopts = track_options( 
            xscale=xscale, w=param.width, fgColor=GREEN,
            show_labels=show_labels, ylabel='Nimble',
            bgColor=bgColors.next()  
        )
        nimble_track = tracks.simple_track( data=nimdata, options=nimopts ) 
        charts.append( nimble_track )

    # generate the ORF track, will separate strands later so will be sending features
    ofeatures = web.feature_filter(data=sql_feat, name='ORF', kdict=label_cache)
    split = show_labels
    orfopts = track_options( 
            xscale=xscale, w=param.width, fgColor=PURPLE,
            show_labels=show_labels, ylabel='ORF',
            bgColor=bgColors.next() 
        )

    orf_track = tracks.split_tracks( features=ofeatures, options=orfopts, split=show_labels, track_type='vector' ) 
    charts.append( orf_track )
    
    
    # create the multiplot
    mopt = chart_options(w=param.width)
    m = chart.MultiChart(options=mopt, charts=charts)
    
    if show:   
        m.show()
    
    return m

#
# track building, could be also set up in the configuration module
#
# two strand tracks


def test( verbose=0 ):
    "Performs module level testing"
    import doctest
    doctest.testmod( optionflags=doctest.ELLIPSIS + doctest.NORMALIZE_WHITESPACE, verbose=verbose )

if __name__ == "__main__":
    from home import webconf as conf

    start = 1
    width = 2600
    chrom =  'chr01'
    end = start + width
    
    param = atlas.Param(start=start, end=end, chrom=chrom, width=800, nuc_track=1, orf_track=1, min_fit=2)

    #conf.h2az_composite_tracks( param=param, conf=conf, show=True )
    conf.h2az_twostrand_tracks( param=param, conf=conf, show=True )
